package com.example.java.newFeature.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

// 每一个 CompletableFuture 整体上都代表一个异步操作，但其内部可以有0个或多个依赖任务，
// 他们可以通过 thenApply、thenAccept、thenRun 等方法来设置依赖关系。这些依赖任务是串行的
public class CompletableFutureDemo2 {
    // 自定义执行器，用于执行异步任务
    private static final Executor customExecutor = Executors.newFixedThreadPool(3);
    private static final Executor virtualExecutor = Executors.newVirtualThreadPerTaskExecutor();

    // 所有的 CompletableFuture 的第一个参数都是 Supplier<T>，即一个函数式接口，用于产生 Runnable 任务
    // 第二个可选参数是 Executor，用于指定任务的执行器
    public static void main(String[] args) throws InterruptedException {
        // 异步计算：在自定义执行器中执行一个耗时任务
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2); // 模拟耗时操作
                return "Result of future1";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, customExecutor);
        
        // 异步计算：在默认执行器中执行另一个耗时任务
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3); // 模拟耗时操作
                return "Result of future2";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        
        // 结果处理：将两个异步任务的结果组合起来
        // 异步任务组合：使用 thenCombine 方法将两个异步任务组合起来。两个任务的执行顺序是异步的，但组合操作是同步的。
        // 两个异步任务的结果会作为参数传递给 thenCombine 方法的第二个参数，并返回一个新的 CompletableFuture
        CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
            return result1 + " and " + result2;
        });
        
        // 异常处理：处理组合后的异步任务可能出现的异常
        combinedFuture.exceptionally(ex -> {
            System.err.println("An error occurred: " + ex.getMessage());
            return "Error handling result";
        });
        
        // 非阻塞等待：使用 thenAccept 来注册回调函数，当结果可用时执行
        combinedFuture.thenAccept(result -> {
            System.out.println("Combined result: " + result);
        });
        
        // 回调和通知：使用 thenRun 来注册一个任务，当上一个任务完成时执行
        combinedFuture.thenRun(() -> {
            System.out.println("Combined task completed!");
        });

        
        // 在这里我们可以做一些其他的工作，而不需要阻塞等待异步任务完成  



        // 最后，为了示例的完整性，我们阻塞主线程一段时间，以确保异步任务有机会完成
        // 在实际应用中，通常不会这样做，而是会让异步任务在后台运行
        try {

            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }



        // 关闭自定义执行器
        customExecutor.wait();

    }
}
